package org.zxp.javacheck.stringtest;

import org.junit.Test;

/**
 * @program: effectiveJava
 * @description:
 * @author: X-Pacific zhang
 * @create: 2019-06-25 14:32
 **/
public class HelloWorld {
    public static void main(String[] args) {
        //在堆中会有一个”abc”实例，全局StringTable中存放着”abc”的一个引用值
        String str1 = "abc";
        //生成两个实例，一个是”def”的实例对象，并且StringTable中存储一个”def”的引用值，还有一个是new出来的一个”def”的实例对象(指向str2)
        String str2 = new String("def");
        //查找StringTable，里面有”abc”的全局驻留字符串引用，所以str3的引用地址与之前的那个已存在的相同
        String str3 = "abc";
        //调用intern()函数，返回StringTable中”def”的引用值，如果没有就将str2的引用值添加进去
        String str4 = str2.intern();
        //最后str5在解析的时候就也是指向存在于StringTable中的”def”的引用值
        String str5 = "def";
        //生成一个实例，new出来的一个”def”的实例对象(指向str6)，(def母本与StringTable放入”def”引用值已经创建)，
        String str6 = new String("def");

        System.out.println(str1 == str3);//true

        System.out.println(str2 == str4);//false
        System.out.println(str4 == str5);//true

        System.out.println(str5 == str2);//false
        System.out.println(str6 == str2);//false

        System.out.println(str6 == str2.intern());//false
        System.out.println(str6.intern() == str2.intern());//true
    }

//    intern
//    从字符串常量池（StringTable）中找，
//    找到了直接返回，
//    找不到重新构建这个字符串并将引用加入字符串常量池并返回，并不能直接更改调用intern对象的指向
    @Test
    public void testIntern() {
        String s1 = new String("ja") + new String("vaa");//堆中一个javaa字符串对象，javaa不再常量池中
        System.out.println(s1 == s1.intern());//javaa不再常量池中在堆中，所以s1.intern会直接把在堆中javaa的引用放入常量池，所以结果为true
        //返回true 要看常量池是否已经有值

        String s2 = new String("ja") + new String("va");//堆中 java这个词一定会在字符串常量中
        System.out.println(s2 == s2.intern());//java再常量池中，所以s2.intern会直接返回常量池指针，而s2是新在堆中创建的对象，所以结果为false
        //返回false

        //说明1234已经被加载到字符串常量池中
        String t1 = "1234";//已经加载到字符串常量池
        String s3 = new String("12") + new String("34");//1234新对象
        System.out.println(s3 == s3.intern());//返回false

        //new String("ja") + new String("vaa"); 编译后 是springbuider相加，返回一个对象
        //“1”+“2”编译后是“12”
    }

    /**
     * 测试字符串常量池到底是在类加载阶段就加载好的还是运行后加载好的
     */
    @Test
    public void testIntern2(){
        //说明4321没有加载到字符串常量池中，说明并不是类加载阶段做的，而是运行到的时候才做
        String s4 = new String("43") + new String("21");
        System.out.println(s4 == s4.intern());//返回true
        String t2 = "4321";

        dooo();//这里相当于把zxp1加载到了字符串常量池
        String s5 = new String("zx") + new String("p1");//
        System.out.println(s5 == s5.intern());//返回true
    }

    public void dooo(){
        String t2 = "zxp1";
    }

    @Test
    public void test(){
        //abc 对象  abc字符串常量池 new String("abc")堆中对象指向str2
        String str2= new String("abc");
        //不再生成abc对象 abc常量池指向str1
        String str1= "abc";
        String str3= str2.intern();
        System.out.println(str1==str2);
        System.out.println(str2==str3);
        System.out.println(str1==str3);
    }


}
